package design_4_builder.demo1.builder;

import java.util.Arrays;

public abstract class AbstractStringBuilder  {

	/**
	 * 当前存储数据的对象
	 */
	char[] value;

	/**
	 * 当前字符长度
	 */
	int count;


	public AbstractStringBuilder() {
	}

	public AbstractStringBuilder(int capacity) {
		value = new char[capacity];
	}

	/**
	 * 插入字符串
	 *
	 * @author wangsong
	 * @email 1720696548@qq.com
	 * @date 2022/4/12 11:15
	 */
	public AbstractStringBuilder append(String str) {
		if (str == null) {
			throw new NullPointerException();
		}
		int len = str.length();
		ensureCapacityInternal(count + len);
		// 把str 开头索引0 到 结束索引 len 当然数组value中,放入位置为当前长度索引count
		str.getChars(0, len, value, count);
		count += len;
		return this;
	}


	public AbstractStringBuilder append(boolean b) {
		if (b) {
			ensureCapacityInternal(count + 4);
			value[count++] = 't';
			value[count++] = 'r';
			value[count++] = 'u';
			value[count++] = 'e';
		} else {
			ensureCapacityInternal(count + 5);
			value[count++] = 'f';
			value[count++] = 'a';
			value[count++] = 'l';
			value[count++] = 's';
			value[count++] = 'e';
		}
		return this;
	}


	public AbstractStringBuilder append(char c) {
		ensureCapacityInternal(count + 1);
		value[count++] = c;
		return this;
	}


	@Override
	public abstract String toString();


	/**
	 * 以下是扩容逻辑
	 * ------------
	 * jvm虚拟机最大存储大小
	 */
	private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

	/**
	 * 扩容
	 *
	 * @param minimumCapacity
	 */
	private void ensureCapacityInternal(int minimumCapacity) {
		// overflow-conscious code
		if (minimumCapacity - value.length > 0) {
			value = Arrays.copyOf(value, newCapacity(minimumCapacity));
		}
	}


	/**
	 * 返回至少与给定最小容量相等的容量。返回当前容量增加相同数量+ 2，
	 * 如果*足够。*将不会返回大于{@code MAX_ARRAY_SIZE} *的容量，除非给定的最小容量大于这个值。
	 * minCapacity期望的最小容量
	 * <p>
	 * 当minCapacity小于零或*大于Integer时抛出OutOfMemoryError错误。MAX_VALUE
	 *
	 * @param minCapacity
	 * @return
	 */
	private int newCapacity(int minCapacity) {
		// overflow-conscious code
		int newCapacity = (value.length << 1) + 2;
		if (newCapacity - minCapacity < 0) {
			newCapacity = minCapacity;
		}
		return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
				? hugeCapacity(minCapacity)
				: newCapacity;
	}


	private int hugeCapacity(int minCapacity) {
		if (Integer.MAX_VALUE - minCapacity < 0) {
			throw new OutOfMemoryError();
		}
		return (minCapacity > MAX_ARRAY_SIZE)
				? minCapacity : MAX_ARRAY_SIZE;
	}


}
